/* mipex2.c - Reading in and optimizing a MIP problem */

/* To run this example, command line arguments are required.
   i.e.,   mipex2   filename
   where 
       filename is the name of the file, with .mps, .lp, or .sav extension
   Example:
       mipex2  mexample.mps
 */

#include <ilcplex/cplex.h>

/* Bring in the declarations for the string and character functions 
   and malloc */
#include <time.h>
#include <sys/time.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>

/* Include declarations for functions in this program */

static void
   free_and_null (char **ptr),
   usage         (char *progname);

double mysecond();

int
main (int argc, char *argv[])
{

   int      solstat;
   double   objval;
   double   *x     = NULL;
   double t0, t1, t2;

   CPXENVptr     env = NULL;
   CPXLPptr      lp = NULL;
   int           status;
   int           j;
   int           cur_numcols;

   int      my_rank, p, namelen;
   char name[MPI_MAX_PROCESSOR_NAME];

   MPI_Init(&argc, &argv);
   MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
   MPI_Comm_size(MPI_COMM_WORLD, &p);
   MPI_Get_processor_name (name, &namelen);

   /* Check the command line arguments */
   if ( argc != 2 ) {
      usage (argv[0]);
      goto TERMINATE;
   }

   /* Initialize the CPLEX environment */
   env = CPXopenCPLEX (&status);

   if ( env == NULL ) {
      char  errmsg[1024];
      fprintf (stderr, "Could not open CPLEX environment.\n");
      CPXgeterrorstring (env, status, errmsg);
      fprintf (stderr, "%s", errmsg);
      goto TERMINATE;
   }

   /* Turn on output to the screen */
   status = CPXsetintparam (env, CPX_PARAM_SCRIND, CPX_OFF);
   if ( status ) {
      fprintf (stderr, 
               "Failure to turn on screen indicator, error %d.\n", status);
      goto TERMINATE;
   }

   /* --------------------------------------------
    *  Add priori control of mip optimizor here 
    * --------------------------------------------
    */

   /* Turn on or off preprocessor  */
   CPXsetintparam(env,CPX_PARAM_PREIND, 1);
   CPXsetintparam(env, CPX_PARAM_PREIND, CPX_OFF);       // presolve 
   CPXsetintparam(env, CPX_PARAM_PRESLVND, CPX_OFF);     // presolve at the node
   CPXsetintparam(env, CPX_PARAM_RELAXPREIND, CPX_OFF);  // presolve of relaxed lp at the root node  
   CPXsetintparam(env, CPX_PARAM_COEREDIND, CPX_OFF);   // coefficient reduction
   CPXsetintparam(env, CPX_PARAM_AGGIND, CPX_OFF);      // aggregator
   status = CPXsetintparam(env, CPX_PARAM_HEURFREQ , -1 );    //-1 to turn it off
   /* Set Output options */
   CPXsetintparam(env,CPX_PARAM_MIPINTERVAL , 100);
   CPXsetintparam(env,CPX_PARAM_MIPDISPLAY , 2);
   CPXsetintparam(env,CPX_PARAM_THREADS, 4);

   /* Set Terminating criterion*/

   CPXsetdblparam(env, CPX_PARAM_EPGAP, 0.0001 );   

   /* Set controlling strategies */
   CPXsetintparam(env, CPX_PARAM_MIPEMPHASIS, 0);	 
   CPXsetintparam(env, CPX_PARAM_BRDIR, 1);
   CPXsetintparam(env, CPX_PARAM_PROBE, 0);

   /* Set cut options */
   CPXsetintparam(env,CPX_PARAM_CLIQUES , -1);	 
   CPXsetintparam(env,CPX_PARAM_COVERS , -1);	 
   CPXsetintparam(env,CPX_PARAM_DISJCUTS , -1);	 
   CPXsetintparam(env,CPX_PARAM_FLOWPATHS , -1);	 
   CPXsetintparam(env,CPX_PARAM_GUBCOVERS , -1);	 
   CPXsetintparam(env,CPX_PARAM_FRACCUTS , -1);	 
   CPXsetintparam(env,CPX_PARAM_IMPLBD , -1);	 
   CPXsetintparam(env,CPX_PARAM_FLOWCOVERS , -1);	 
   CPXsetintparam(env, CPX_PARAM_MIRCUTS , -1 );    
   CPXsetintparam(env, CPX_PARAM_ZEROHALFCUTS , -1 );    


   lp = CPXcreateprob (env, &status, argv[1]);

   if ( lp == NULL ) {
      fprintf (stderr, "Failed to create LP.\n");
      goto TERMINATE;
   }

   /* Now read the file, and copy the data into the created lp */

   status = CPXreadcopyprob (env, lp, argv[1], NULL);
   if ( status ) {
      fprintf (stderr, "Failed to read and copy the problem data.\n");
      goto TERMINATE;
   }

   t0 = mysecond();
   /* Optimize the problem and obtain solution. */
   status = CPXmipopt (env, lp);

   if ( status ) {
      fprintf (stderr, "Failed to optimize MIP.\n");
      goto TERMINATE;
   }
   t1 = mysecond();

   solstat = CPXgetstat (env, lp);
   printf ("Solution status %d.\n", solstat);

   status  = CPXgetobjval (env, lp, &objval);
   if ( status ) {
      fprintf (stderr,"Failed to obtain objective value.\n");
      goto TERMINATE;
   }

   printf ("Objective value %.10g\n", objval);
   cur_numcols = CPXgetnumcols (env, lp);

   /* Allocate space for solution */

   x = (double *) malloc (cur_numcols*sizeof(double));

   if ( x == NULL ) {
      fprintf (stderr, "No memory for solution values.\n");
      goto TERMINATE;
   }

   status = CPXgetx (env, lp, x, 0, cur_numcols-1);
   if ( status ) {
      fprintf (stderr, "Failed to obtain solution.\n");
      goto TERMINATE;
   }


   printf("The optimizatio from process %d of %d running on %s takes %12.6f seconds.\n", my_rank, p, name, t1-t0);

 TERMINATE:

   /* Free up the solution */

   free_and_null ((char **) &x);

   /* Free up the problem as allocated by CPXcreateprob, if necessary */

   if ( lp != NULL ) {
      status = CPXfreeprob (env, &lp);
      if ( status ) {
         fprintf (stderr, "CPXfreeprob failed, error code %d.\n", status);
      }
   }

   /* Free up the CPLEX environment, if necessary */

   if ( env != NULL ) {
      status = CPXcloseCPLEX (&env);

      /* Note that CPXcloseCPLEX produces no output,
         so the only way to see the cause of the error is to use
         CPXgeterrorstring.  For other CPLEX routines, the errors will
         be seen if the CPX_PARAM_SCRIND indicator is set to CPX_ON. */

      if ( status ) {
      char  errmsg[1024];
         fprintf (stderr, "Could not close CPLEX environment.\n");
         CPXgeterrorstring (env, status, errmsg);
         fprintf (stderr, "%s", errmsg);
      }
   }

   MPI_Finalize();
     
   return (status);

}  /* END main */


/* This simple routine frees up the pointer *ptr, and sets *ptr to NULL */

static void
free_and_null (char **ptr)
{
   if ( *ptr != NULL ) {
      free (*ptr);
      *ptr = NULL;
   }
} /* END free_and_null */ 


static void
usage (char *progname)
{
   fprintf (stderr,"Usage: %s filename\n", progname);
   fprintf (stderr,"   where filename is a file with extension \n");
   fprintf (stderr,"      MPS, SAV, or LP (lower case is allowed)\n");
   fprintf (stderr,"  This program uses the CPLEX MIP optimizer.\n");
   fprintf (stderr," Exiting...\n");
} /* END usage */


double mysecond()
{
   struct timeval tp;
   struct timezone tzp;
   int i;
   i = gettimeofday(&tp,&tzp);
   return ( (double) tp.tv_sec + (double) tp.tv_usec * 1.e-6 );
}
